package no.hib.mod250.chat.client.view;

import java.util.Date;
import java.util.Map;

import no.hib.mod250.chat.client.controller.ChatController;
import no.hib.mod250.chat.client.i18.ChatConstants;
import no.hib.mod250.chat.client.model.Model;
import no.hib.mod250.chat.client.model.Model.DeleteMessageAction;
import no.hib.mod250.chat.client.service.ChatService;
import no.hib.mod250.chat.client.util.R;
import no.hib.mod250.chat.client.util.Util;
import no.hib.mod250.chat.client.view.View.DataObserver;

import org.adamtacy.client.ui.effects.events.EffectCompletedEvent;
import org.adamtacy.client.ui.effects.events.EffectCompletedHandler;
import org.adamtacy.client.ui.effects.impl.Fade;
import org.adamtacy.client.ui.effects.transitionsphysics.LinearTransitionPhysics;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLTable;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.Widget;

public class MessagesView extends View implements DataObserver {

	// CLASSES

	/**
	 * Represents a single Message View
	 */
	public class MessageView {

		private Widget getTime(final Date date) {
			final DateTimeFormat formatter = DateTimeFormat.getFormat("HH:mm");

			Label label = new Label(formatter.format(date), false);
			return label;
		}

		private Widget getUser(final Model.User user) {
			Image avatar = Util.Gravatar.generate(user.getEmail(), 20);
			Label userLbl = new Label(user.getNickname());
			
			Grid grid = new Grid(1, 2);
			grid.setWidget(0, 0, avatar);
			grid.setWidget(0, 1, userLbl);
			
			grid.getRowFormatter().setVerticalAlign(0, HasVerticalAlignment.ALIGN_TOP);

			return grid;
		}

		private Widget getDelete(final Model.Message message) {
			if (!message.getUser().equals(
					getController().getChatUser().getEventObject())) {
				return null;
			}

			Button button = new Button("x");
			button.addClickHandler(new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					getController().doMessageDelete(message.getId());
				}
			});
			return button;
		}
		
		private HTML getMessage(final String message)
		{
			Map<String, Anchor> links = Util.URI.LinkParser.parse(message);
			String messageNew = message;

			for (String key : links.keySet()) {
				GWT.log(key + ": " + links.get(key));
				if (key != null && key != "" && links.get(key) != null)
				{				
				messageNew = messageNew.replace(key, links.get(key).toString());
				}
			}
			
			HTML html = new HTML(messageNew);
			return html;
		}

		public void doDraw(final FlexTable table, final Model.Message message,
				boolean newMsg) {
			int rowcount = table.getRowCount();

			// Date
			Date date = new Date(message.getTimestamp());
			table.setWidget(rowcount, 0, getTime(date));
			table.getCellFormatter().addStyleName(rowcount, 0, R.Class.Messages.date);
			
			// User
			table.setWidget(rowcount, 1, getUser(message.getUser()));
			table.getCellFormatter().addStyleName(rowcount, 1, R.Class.Messages.user);
			
			// Message
			table.setWidget(rowcount, 2, getMessage(message.getMessage()));
			table.getCellFormatter().addStyleName(rowcount, 2, R.Class.Messages.message);
			
			// Delete
			table.setWidget(rowcount, 3, getDelete(message));
			table.getCellFormatter().addStyleName(rowcount, 3, R.Class.Messages.delete);
			
			// Set row id
			table.getRowFormatter().getElement(rowcount).setId(
					getMessageIdPrefix(message.getId()));
			
			table.getRowFormatter().setVerticalAlign(rowcount, HasVerticalAlignment.ALIGN_TOP);

			// FADE

			if (newMsg) {

				Fade fade = new Fade(table.getRowFormatter().getElement(
						rowcount));
				fade.setDuration(0.5);
				fade.setTransitionType(new LinearTransitionPhysics());
				fade.play(1.0, 0.0);

			}

			// /FADE

			table.addClickHandler(new ClickHandler() {

				@Override
				public void onClick(ClickEvent event) {
					HTMLTable.Cell cell = table.getCellForEvent(event);
					Element row = cell.getElement().getParentElement();
					if (!row.getId().equalsIgnoreCase("")) {
						doMessageClick(row.getId());
					}
				}
			});
		}
	}

	// /CLASSES

	// VARIABLES

	// ... VIEW

	private ScrollPanel panel = new ScrollPanel();
	private FlexTable messagesTable = new FlexTable();

	// ... /VIEW

	private static String MESSAGE_ID_PREFIX = "message_";
	private static ChatConstants.Messages messagesConstants = GWT
			.create(ChatConstants.Messages.class);

	private Model.MessageList messages = new Model.MessageList();

	// /VARIABLES

	// CONSTRUCTOR

	public MessagesView(ChatController controller) {
		super(controller);

		// Add View as Data Observer
		controller.addDataObserver(this);

		// Set composite to wrap panel
		initWidget(panel);

		// Draw View
		doDraw();
	}

	// /CONSTRUCTOR

	// FUNCTIONS

	// ... GET

	protected static String getMessageIdPrefix(long messageId) {
		return MESSAGE_ID_PREFIX + messageId;
	}

	protected static long getMessageId(String messageIdPrefix) {
		try {
			return Long.parseLong(messageIdPrefix
					.replace(MESSAGE_ID_PREFIX, ""));
		} catch (NumberFormatException e) {
			return -1L;
		}
	}

	// ... /GET

	// ... DO

	@Override
	protected void doDraw() {
		// Scroll panel
		panel.setStyleName("messagesPanel");
		panel.setAlwaysShowScrollBars(false);
		panel.setWidth("50%");

		// Messages table
		panel.setWidget(messagesTable);
		messagesTable.setStyleName(R.Class.Messages.messages);
		messagesTable.setText(0, 0, messagesConstants.noMessages());
	}

	/**
	 * Delete message from table
	 * 
	 * @param deleteMessageAction
	 */
	private void doDeleteMessage(Model.DeleteMessageAction deleteMessageAction) {
		// Get Message row
		final Element messageRow = DOM
				.getElementById(getMessageIdPrefix(deleteMessageAction.getId()));

		// Remove Message from Messages List
		messages.remove(deleteMessageAction.getId());

		// Message must exist in table row
		if (!messageRow.getTagName().equalsIgnoreCase("tr")) {
			return;
		}

		// Fade the row out from table
		Fade fade = new Fade();
		fade.setDuration(0.5);
		fade.setTransitionType(new LinearTransitionPhysics());
		fade.setEffectElement(messageRow);

		fade.addEffectCompletedHandler(new EffectCompletedHandler() {

			@Override
			public void onEffectCompleted(EffectCompletedEvent event) {
				messageRow.removeFromParent();
			}
		});
		fade.play(0.0, 1.0);
	}
	
	private void doDeleteMessages()
	{
		// Remove Messages from Messages List
		messages.clear();
		
		// Clear messages table
		messagesTable.removeAllRows();
		messagesTable.setText(0, 0, messagesConstants.noMessages());
	}

	/**
	 * Message row click
	 * 
	 * @param tableRowId
	 */
	private void doMessageClick(String tableRowId) {
		assert tableRowId != "" || tableRowId != null;
		long messageId = getMessageId(tableRowId);
		assert messageId >= 0;

		Model.Message message = messages.get(messageId);

		getController().doNotifyMessageClick(message);
	}

	// ... /DO

	// ... ON

	@Override
	public void onDataResult(ChatService.Result result) {
		// Get new Messages
		Model.MessageList messagesTemp = result.getMessages();

		// Remove no messages text
		if (!messagesTemp.isEmpty() && messages.isEmpty()) {
			messagesTable.removeAllRows();
		}

		// Add each new Message to table
		MessageView messageView = new MessageView();
		for (Model.Message message : messagesTemp) {
			messageView.doDraw(messagesTable, message, !messages.isEmpty());
		}

		// Scroll to bottom
		if (!messagesTemp.isEmpty())
		{
			panel.scrollToBottom();
		}
		
		// Add new Messages to Messages List
		messages.addAll(messagesTemp);

		// Delete Message Actions
		for (Model.Action action : result.getActions()) {
			if (action instanceof Model.DeleteMessageAction) {
				doDeleteMessage((DeleteMessageAction) action);
			}
			else if (action instanceof Model.DeleteMessagesAction) {
				doDeleteMessages();
			}
		}
	}

	// ... /ON

}
